package com.golxen.framework.common.server.game;


import com.golxen.framework.common.CommandPlugin;
import com.golxen.framework.common.ShutDownPlugin;
import com.golxen.framework.common.server.BaseServer;
import com.golxen.framework.manager.TempMgr;
import com.golxen.framework.common.server.eServerType;
import com.golxen.framework.executor.GeneralThreadFactory;
import com.golxen.framework.log.LogMgr;
import com.golxen.framework.manager.ManagerPlugin;
import com.golxen.framework.netty.session.game.GameServerHandler;
import com.golxen.framework.timers.TimerPlugin;
import com.golxen.framework.user.player.GamePlayer;
import com.golxen.framework.user.player.GamePlayerMgr;
import com.golxen.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public final class GameServer extends BaseServer {

    private static GameServer gameServer;

    public static GameServer getInstance() {
        if (gameServer == null) {
            gameServer = new GameServer();
        }

        return gameServer;
    }

    @Override
    public boolean start() {

        setServerType(eServerType.GAME);

        CommandPlugin.start();

        if (!super.start()) {
            return false;
        }


        if (!initNetty(new GameServerHandler(), eServerType.GAME)) {
            return false;
        }

        // 注册异常关闭处理过程
        ShutDownPlugin.registShutDownFn(() -> {
            LogUtil.CONSOLE.info("GameServer kill 关闭服务器");
            GameServer.getInstance().newStop();
        });

        return true;
    }

    @Override
    public boolean stop() {
        return this.newStop();
    }

    public boolean newStop() {
        try {
            // 关闭netty端口
            nettyServices.newStop();

            // 暂停3秒
            Thread.sleep(3000);
            // 停止定时器
            LogUtil.CONSOLE.info("stop timer");
            TimerPlugin.stop();

            // 保存玩家数据
            LogUtil.CONSOLE.info("save player data");
            ExecutorService stopSaveUserExecutor = Executors.newFixedThreadPool(
                    Runtime.getRuntime().availableProcessors() * 4, new GeneralThreadFactory("gameServer-stop-save"));
            List<GamePlayer> playerList = GamePlayerMgr.getCopyPlayerList();
            AtomicInteger saveNum = new AtomicInteger(0);
            playerList.forEach(player -> stopSaveUserExecutor.execute(() -> {
                // 保存在线玩家数据
                GamePlayerMgr.onLogout(player, true);
                saveNum.addAndGet(1);
            }));
            stopSaveUserExecutor.shutdown();
            LogUtil.CONSOLE.info("save mgr data");
            // 保存mgr数据
            for (TempMgr baseMgr : ManagerPlugin.getMgrs()) {
                try {
                    baseMgr.save();
                } catch (Throwable t) {
                    LogUtil.CONSOLE.error(StringUtils.EMPTY, t);
                }
            }


            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                LogUtil.CONSOLE.error(StringUtils.EMPTY, e);
            }

            // 保存log日志
            LogMgr.shutdown();

            while (true) {
                if (stopSaveUserExecutor.isTerminated()) {
                    LogUtil.CONSOLE.info("GameServer stop success");
                    LogUtil.CONSOLE.info("saveNum: {}, totalNum: {}", saveNum.intValue(), playerList.size());
                    if (saveNum.intValue() == playerList.size()) {
                        break;
                    }
                } else {
                    Thread.sleep(1000);
                }
            }

//            BaseServer.deleteFile("./pid");
        } catch (Exception e) {
            LogUtil.CONSOLE.error("GameServer stop error", e);
            return false;
        } finally {
            LogUtil.CONSOLE.info("GameServer shutdown over....");
        }

        return true;
    }

    public static void main() {

        GameServer gameServer = GameServer.getInstance();

        if (!gameServer.start()) {
            throw new RuntimeException("GameServer start up fail");
        }

    }

    @Override
    public List<TempMgr> getMgrList() {
        return null;
    }

}
